﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using CellarDoor.Gui.Animation;

namespace CellarDoor.Gui.Elements
{
    public partial class UiElement
    {
        public void Toggle()
        {
            Visible = !Visible;
        }

        #region Fade
        public AnimateOpacity FadeIn()
        {
            return FadeTo(1);
        }

        public AnimateOpacity FadeIn(float duration)
        {
            return FadeTo(1, duration);
        }

        public AnimateOpacity FadeIn(float duration, EaseFunction ease)
        {
            return FadeTo(1, duration, ease);
        }

        public AnimateOpacity FadeIn(float duration, EaseFunction ease, AnimateEvent callback)
        {
            return FadeTo(1, duration, ease, callback);
        }

        public AnimateOpacity FadeOut()
        {
            return FadeTo(0);
        }

        public AnimateOpacity FadeOut(float duration)
        {
            return FadeTo(0, duration);
        }

        public AnimateOpacity FadeOut(float duration, EaseFunction ease)
        {
            return FadeTo(0, duration, ease);
        }

        public AnimateOpacity FadeOut(float duration, EaseFunction ease, AnimateEvent callback)
        {
            return FadeTo(0, duration, ease, callback);
        }

        public AnimateOpacity FadeToggle()
        {
            return FadeTo(Opacity > 0 ? 0 : 1);
        }

        public AnimateOpacity FadeToggle(float duration)
        {
            return FadeTo(Opacity > 0 ? 0 : 1, duration);
        }

        public AnimateOpacity FadeToggle(float duration, EaseFunction ease)
        {
            return FadeTo(Opacity > 0 ? 0 : 1, duration, ease);
        }

        public AnimateOpacity FadeToggle(float duration, EaseFunction ease, AnimateEvent callback)
        {
            return FadeTo(Opacity > 0 ? 0 : 1, duration, ease, callback);
        }

        public AnimateOpacity FadeTo(float value)
        {
            return FadeTo(value, 1000, EaseFunction.OutQuad, null);
        }

        public AnimateOpacity FadeTo(float value, float duration)
        {
            return FadeTo(value, duration, EaseFunction.OutQuad, null);
        }

        public AnimateOpacity FadeTo(float value, float duration, EaseFunction ease)
        {
            return FadeTo(value, duration, ease, null);
        }

        private AnimateOpacity fadeToAnimator;
        public AnimateOpacity FadeTo(float value, float duration, EaseFunction ease, AnimateEvent callback)
        {
            if (fadeToAnimator != null)
            {
                fadeToAnimator.Reset();
            }
            else
            {
                fadeToAnimator = controllers.Add(new AnimateOpacity(this)) as AnimateOpacity;
            }

            fadeToAnimator.StartOpacity = this.Opacity;
            fadeToAnimator.EndOpacity = value;
            fadeToAnimator.Duration = duration;
            fadeToAnimator.EaseFunction = ease;

            fadeToAnimator.StopAnimation += (ani) =>
            {
                controllers.Remove(ani);
                fadeToAnimator = null;
            };
            if (callback != null){
                fadeToAnimator.StopAnimation += callback;
            }

            fadeToAnimator.Start();
            return fadeToAnimator;
        }
        #endregion

        #region Slide
        public AnimatePosition SlideTo(Vector2 position)
        {
            return SlideTo(position, 1000, EaseFunction.OutQuad, null);
        }

        public AnimatePosition SlideTo(Vector2 position, float duration)
        {
            return SlideTo(position, duration, EaseFunction.OutQuad, null);
        }

        public AnimatePosition SlideTo(Vector2 position, float duration, EaseFunction ease)
        {
            return SlideTo(position, duration, ease, null);
        }

        private AnimatePosition slideToAnimator;
        public AnimatePosition SlideTo(Vector2 position, float duration, EaseFunction ease, AnimateEvent callback)
        {
            if (slideToAnimator != null)
            {
                slideToAnimator.Reset();
            }
            else
            {
                slideToAnimator = controllers.Add(new AnimatePosition(this)) as AnimatePosition;
            }

            slideToAnimator.StartPosition = this.Location;
            slideToAnimator.EndPosition = position;
            slideToAnimator.Duration = duration;
            slideToAnimator.EaseFunction = ease;

            slideToAnimator.StopAnimation += (ani) =>
            {
                controllers.Remove(ani);
                slideToAnimator = null;
            };
            if (callback != null)
            {
                slideToAnimator.StopAnimation += callback;
            }

            slideToAnimator.Start();
            return slideToAnimator;
        }
        #endregion

        #region Inflate
        public AnimateSize InflateTo(Vector2 size)
        {
            return InflateTo(size, 1000, EaseFunction.OutQuad, null);
        }

        public AnimateSize InflateTo(Vector2 size, float duration)
        {
            return InflateTo(size, duration, EaseFunction.OutQuad, null);
        }

        public AnimateSize InflateTo(Vector2 size, float duration, EaseFunction ease)
        {
            return InflateTo(size, duration, ease, null);
        }

        private AnimateSize sizeToAnimator;
        public AnimateSize InflateTo(Vector2 size, float duration, EaseFunction ease, AnimateEvent callback)
        {
            if (sizeToAnimator != null)
            {
                sizeToAnimator.Reset();
            }
            else
            {
                sizeToAnimator = controllers.Add(new AnimateSize(this)) as AnimateSize;
            }

            sizeToAnimator.StartValue = this.Size;
            sizeToAnimator.EndValue = size;
            sizeToAnimator.Duration = duration;
            sizeToAnimator.EaseFunction = ease;

            sizeToAnimator.StopAnimation += (ani) =>
            {
                controllers.Remove(ani);
                sizeToAnimator = null;
            };
            if (callback != null)
            {
                sizeToAnimator.StopAnimation += callback;
            }

            sizeToAnimator.Start();
            return sizeToAnimator;
        }
        #endregion

        #region Blend
        public AnimateColor BlendTo(Vector3 color)
        {
            return BlendTo(color, 1000, EaseFunction.OutQuad, null);
        }

        public AnimateColor BlendTo(Vector3 color, float duration)
        {
            return BlendTo(color, duration, EaseFunction.OutQuad, null);
        }

        public AnimateColor BlendTo(Vector3 color, float duration, EaseFunction ease)
        {
            return BlendTo(color, duration, ease, null);
        }

        private AnimateColor colorToAnimator;
        public AnimateColor BlendTo(Vector3 color, float duration, EaseFunction ease, AnimateEvent callback)
        {
            if (colorToAnimator != null)
            {
                colorToAnimator.Reset();
            }
            else
            {
                colorToAnimator = controllers.Add(new AnimateColor(this)) as AnimateColor;
            }

            colorToAnimator.StartColor = this.Color;
            colorToAnimator.EndColor = color;
            colorToAnimator.Duration = duration;
            colorToAnimator.EaseFunction = ease;

            slideToAnimator.StopAnimation += (ani) =>
            {
                controllers.Remove(ani);
                colorToAnimator = null;
            };
            if (callback != null)
            {
                colorToAnimator.StopAnimation += callback;
            }

            colorToAnimator.Start();
            return colorToAnimator;
        }
        #endregion

        #region Rotate
        #endregion
    }
}
